package final_project;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class Corpus {
    private Map<String, Patent> data;

    public Corpus() {
        this.data = new HashMap<String, Patent>();
    }

    public Corpus(Map<String, Patent> data) {
        this.data = data;
    }

    /**
     * 是的，data.put(applicationNo.trim().toUpperCase(), patent);
     * 这行代码的作用是向 data 这个 Map（如 HashMap）中存入一个 键值对（Key-Value Pair）
     * */

    /**
     * put 方法的功能
     *
     * 存入键值对：将处理后的 applicationNo 作为 键（Key），
     *
     * 对应的 patent 对象作为 值（Value） 存入 data。
     *
     * 覆盖旧值：如果 data 中已存在相同的键，新值（patent）会覆盖旧值。
     *
     * 键的唯一性：Map 中的键是唯一的，因此同一个 applicationNo（处理后的）只能对应一个 patent。
     * */

    public void add(String applicationNo, Patent patent) {
        if (applicationNo == null || applicationNo.trim().equals("")) {
            return;
        }

        data.put(applicationNo.trim().toUpperCase(), patent);
    }

    public int size() {
        return data.size();
    }

    /**
     * 是的，data.containsKey(applicationNo.trim().toUpperCase())
     * 这行代码的逻辑是：将输入的 applicationNo 去掉前后空格并转为全大写后，
     * 再与 data 这个 HashMap 中的键（Key）进行精确匹配。
     * */

    public boolean contains(String applicationNo) {
        if (applicationNo == null || applicationNo.trim().equals("")) {
            return false;
        }

        //containsKey方法本身不进行忽略大小写的比较，而是依赖于键的精确匹配。
        return data.containsKey(applicationNo.trim().toUpperCase());
    }

    //单纯比较HashMap中的values中的某一处值
    public boolean contains(Ipc ipc) {
        if (ipc == null) {
            return false;
        }

        for (Patent patent: data.values()) {
            HashSet<Ipc> ipcs = patent.getIpcs();
            //这个contains是set集合类有的而map没有的
            if (ipcs.contains(ipc)) {
                return true;
            }
        }

        return false;
    }

    public boolean contains(Cpc cpc) {
        if (cpc == null) {
            return false;
        }

        for (Patent patent: data.values()) {
            HashSet<Cpc> cpcs = patent.getCpcs();
            if (cpcs.contains(cpc)) {
                return true;
            }
        }

        return false;
    }

    //因为这里在Patent里被当作唯一值处理，因此其get方法返回的是Date类型而不是Set类型
    public boolean contains(Date applicationDate) {
        if (applicationDate == null) {
            return false;
        }

        for (Patent patent: data.values()) {
            if (patent.getApplicationDate().equals(applicationDate)) {
                return true;
            }
        }

        return false;
    }

    public Corpus find(String applicationNo) {
        //如果不包含key,则直接返回null,用到了之前写好的方法
        if (!contains(applicationNo)) {
            return null;
        }

        Map<String, Patent> subData = new HashMap<String, Patent>();

        //get方法动态绑定到HashMap的get方法，get到value
        String applicationNoAfter = applicationNo.trim().toUpperCase();
        //存入让其自动查找
        subData.put(applicationNoAfter, data.get(applicationNoAfter));

        return new Corpus(subData);
    }

    public Corpus find(Ipc ipc) {
        if (!contains(ipc)) {
            return null;
        }

        Map<String, Patent> subData = new HashMap<String, Patent>();

        //这里为什么要用Entry方法？不直接Map<String,Patent>？
        for (Map.Entry<String, Patent> entry: data.entrySet()) {
            //这里巧就巧在getIpcs方法返回的是Set集合类，因此可以利用contains方法节省脑力
            Set<Ipc> ipcs = entry.getValue().getIpcs();
            if (ipcs.contains(ipc)) {
                //将找到的k和v转载到新的HashMap对象中
                subData.put(entry.getKey(), entry.getValue());
            }
        }

        return new Corpus(subData);
    }

    public Corpus find(Cpc cpc) {
        if (!contains(cpc)) {
            return null;
        }

        Map<String, Patent> subData = new HashMap<String, Patent>();

        for (Map.Entry<String, Patent> entry: data.entrySet()) {
            Set<Cpc> cpcs = entry.getValue().getCpcs();
            if (cpcs.contains(cpc)) {
                subData.put(entry.getKey(), entry.getValue());
            }
        }

        return new Corpus(subData);
    }

    public Corpus find(Date applicationDate) {
        if (!contains(applicationDate)) {
            return null;
        }

        Map<String, Patent> subData = new HashMap<String, Patent>();

        for (Map.Entry<String, Patent> entry: data.entrySet()) {
            Date date = entry.getValue().getApplicationDate();
            if (date.equals(applicationDate)) {
                subData.put(entry.getKey(), entry.getValue());
            }
        }

        return new Corpus(subData);
    }

    public void remove(String applicationNo) {
        if (!contains(applicationNo)) {
            return;
        }
        //这里更间接，直接一个方法搞定
        data.remove(applicationNo.trim().toUpperCase());
    }

    public void remove(Ipc ipc) {
        if (!contains(ipc)) {
            return;
        }

        Set<String> keys = new HashSet<String>();
        for (Map.Entry<String, Patent> entry: data.entrySet()) {
            //得到Ipcs的Set集合
            Set<Ipc> ipcs = entry.getValue().getIpcs();
            if (ipcs.contains(ipc)) {
                keys.add(entry.getKey());
            }
        }

        for (String key: keys) {
            data.remove(key);
        }
    }

    //为啥会输出整个k,v?
    public void remove(Cpc cpc) {
        if (!contains(cpc)) {
            return;
        }

        //这里用HashSet是因为方便
        Set<String> keys = new HashSet<String>();
        for (Map.Entry<String, Patent> entry: data.entrySet()) {
            Set<Cpc> cpcs = entry.getValue().getCpcs();
            if (cpcs.contains(cpc)) {
                keys.add(entry.getKey());
            }
        }

        for (String key: keys) {
            data.remove(key);
        }
    }

    public void remove(Date applicationDate) {
        if (!contains(applicationDate)) {
            return;
        }

        //声明为Set类型变量可以灵活更换实现，而实例化为HashSet是常见的做法，不会影响功能，反而提高代码的灵活性。
        Set<String> keys = new HashSet<String>();
        for (Map.Entry<String, Patent> entry: data.entrySet()) {
            Date date = entry.getValue().getApplicationDate();
            if (date.equals(applicationDate)) {
                keys.add(entry.getKey());
            }
        }

        for (String key: keys) {
            data.remove(key);
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();

        //返回一个 Set 集合，集合中的每个元素是 Map.Entry 类型的对象（即键值对）。
        //结合源码：Set<Map.Entry<K, V>> entrySet();
        for (Map.Entry<String, Patent> entry: data.entrySet()) {
            sb.append(entry.getKey() + "\t" + entry.getValue() + "\n");
        }

        return sb.toString();
    }

    public static void main(String[] args) {
        Corpus corpus = new Corpus();

        corpus.add("14725838", new Patent("2015-05-29", "A23B 5/04, A23B 5/045", "A23B 5/04, A23B 5/45, A23L 15/20", 'F', 'I'));
        corpus.add("14814205", new Patent("2015-07-30", "A61H 33/00, C01B 33/107, E04B 1/84", "A61H 33/6063, A61H 33/6042", 'F', 'I'));
        corpus.add("15189723", new Patent("2016-06-22", "D04B 1/00", "B65H2301/44514, C01B 33/1071, F16F 15/2, H01L 27/14641", 'L', 'A'));
        corpus.add("14711011", new Patent("2015-05-13", "B32B 17/10, B32B 27/32, F16F 15/02", "G06F 3/485", 'L', 'A'));
        corpus.add("14515267", new Patent("2014-10-15", "F16F 15/02, G09G 5/34, G06F 3/0485", "A01B 15/06, A01B 15/06", 'L', 'I'));

        System.out.println(corpus);

        System.out.println("00000000000000000000");
        Ipc ipc = new Ipc("A23B 5/04");
        System.out.println(corpus.contains(ipc));

        System.out.println("--------------------");
        corpus.remove("14814205");
        System.out.println(corpus);



        System.out.println("++++++++++++++++++++++++");
        corpus.remove(new Ipc("F16F 15/02"));
        System.out.println(corpus);

        System.out.println("========================");
        corpus.remove(new Cpc("A23B 5/04", 'F', 'I'));
        System.out.println(corpus);
    }
}